#include "StdAfx.h"
#include "PhysicalObject.h"
#include "IMovable.h"


//////////////////////////////////////////////////////////////////////////////
PhysicalObject::PhysicalObject(IMovable& movable)
      : m_movable(movable),
      m_acceleration(0),
      m_maxHorizontalSpeed(0),
      m_maxVerticalSpeed(0),
      m_gravity(0, 0, 0),
      m_friction(0),
      m_velocity(0, 0, 0)
{
}

//////////////////////////////////////////////////////////////////////////////

void PhysicalObject::applyForce(const D3DXVECTOR3& forceVec)
{
   m_velocity = forceVec / (-m_gravity.y / 10.f);
}

//////////////////////////////////////////////////////////////////////////////

D3DXVECTOR3 PhysicalObject::getMovementForce()
{
   D3DXVECTOR3 movementForce = m_velocity * (-m_gravity.y / 10.f);
   movementForce.y = 0;
   return movementForce;
}

//////////////////////////////////////////////////////////////////////////////

void PhysicalObject::move(DWORD direction, float timeElapsed)
{
   if ((direction & DIR_FORWARD)  == DIR_FORWARD)  m_velocity += m_movable.getLookVec() * m_acceleration * timeElapsed;
   if ((direction & DIR_BACKWARD) == DIR_BACKWARD) m_velocity -= m_movable.getLookVec() * m_acceleration * timeElapsed;
   if ((direction & DIR_RIGHT)    == DIR_RIGHT)    m_velocity += m_movable.getRightVec() * m_acceleration * timeElapsed;
   if ((direction & DIR_LEFT)     == DIR_LEFT)     m_velocity -= m_movable.getRightVec() * m_acceleration * timeElapsed;
   if ((direction & DIR_UP)       == DIR_UP)       m_velocity += m_movable.getUpVec() * m_acceleration * timeElapsed;
   if ((direction & DIR_DOWN)     == DIR_DOWN)     m_velocity -= m_movable.getUpVec() * m_acceleration * timeElapsed;
}

//////////////////////////////////////////////////////////////////////////////

void PhysicalObject::rotate(DWORD direction, float timeElapsed)
{
   float pitch = 0;
   float yaw = 0;
   float roll = 0;
   if ((direction & DIR_RIGHT)    == DIR_RIGHT)    yaw = 60.0f * timeElapsed;
   if ((direction & DIR_LEFT)     == DIR_LEFT)     yaw = -60.0f * timeElapsed;

   m_movable.rotate(pitch, yaw, roll);
}

//////////////////////////////////////////////////////////////////////////////

void PhysicalObject::update(float timeElapsed)
{
   calculatePhysics(timeElapsed);
}

//////////////////////////////////////////////////////////////////////////////

void PhysicalObject::calculatePhysics(float timeElapsed)
{
   // increase velocity
   m_velocity += m_gravity * timeElapsed;

   // clip it to the limits
   float horizontalSpeedVal = sqrtf(m_velocity.x * m_velocity.x + m_velocity.z * m_velocity.z);
   if (horizontalSpeedVal > m_maxHorizontalSpeed)
   {
      m_velocity.x *= m_maxHorizontalSpeed / horizontalSpeedVal;
      m_velocity.z *= m_maxHorizontalSpeed / horizontalSpeedVal;
   }

   // clip it to the limits
   float verticalSpeedVal = sqrtf(m_velocity.y * m_velocity.y);
   if (verticalSpeedVal > m_maxVerticalSpeed)
   {
      m_velocity.y *= m_maxVerticalSpeed / verticalSpeedVal;
   }

   // move the camera
   D3DXVECTOR3 shiftVec = m_velocity * timeElapsed;
   m_movable.move(shiftVec);


   // apply friction
   D3DXVECTOR3 frictionVec = -m_velocity;
   D3DXVec3Normalize(&frictionVec, &frictionVec);

   float currVelocity = D3DXVec3Length(&m_velocity);

   float decValue = (m_friction * timeElapsed);
   if (decValue > currVelocity) decValue = currVelocity;

   m_velocity += frictionVec * decValue;
}

//////////////////////////////////////////////////////////////////////////////
